
#include "SGSignal.h"

#include <csignal>
#include <sstream>

#include <boost/stacktrace.hpp>  // NOLINT(misc-include-cleaner)

#include "Utility/Logging/SGLogger.h"

using namespace SG::Utility;

extern "C" {
void SGSignal::signalHandler (int signum)
{
    std::stringstream ss;
    ss << '\n' << boost::stacktrace::stacktrace ();
    SGInfo << (ss.str ());

    // the default signal handler
    // see https://cplusplus.com/reference/csignal/signal/
    auto result = signal (signum, SIG_DFL);  // reset the signal handler to the default
                                             // SIG_DFL(signum);
    if (result == SIG_ERR)
    {
        SGWarn << "Error: signalHandler() failed";
        return;
    }
}

void SGSignal::registerSignalHandlers ()
{
    // the signals in the standard C library
    /*
     * Not all running environments are required to generate automatic signals in the cases
     * for which they are designed in the standard C library, and some other environments
     * not only generate these but also many more specific signals.
     *
     * see https://cplusplus.com/reference/csignal/
     */
    auto result = signal (SIGINT, signalHandler);  // interrupt
    if (result == SIG_ERR)
    {
        SGWarn << "Error: registerSignalHandlers() failed";
        return;
    }
    result = signal (SIGILL, signalHandler);  // illegal instruction - invalid function image
    if (result == SIG_ERR)
    {
        SGWarn << "Error: registerSignalHandlers() failed";
        return;
    }
    result = signal (SIGFPE, signalHandler);  // floating point exception
    if (result == SIG_ERR)
    {
        SGWarn << "Error: registerSignalHandlers() failed";
        return;
    }

    result = signal (SIGSEGV, signalHandler);  // segment violation
    if (result == SIG_ERR)
    {
        SGWarn << "Error: registerSignalHandlers() failed";
        return;
    }

    result = signal (SIGTERM, signalHandler);  // Software termination signal from kill
    if (result == SIG_ERR)
    {
        SGWarn << "Error: registerSignalHandlers() failed";
        return;
    }

    // signal(SIGBREAK, signalHandler); // abnormal termination triggered by abort call

    result = signal (SIGABRT, signalHandler);  // abnormal termination triggered by abort call
    if (result == SIG_ERR)
    {
        SGWarn << "Error: registerSignalHandlers() failed";
        return;
    }
}
}
